package main

import "fmt"

func main() {
	wxPay := &WXPay{}
	px := NewPayCtx(wxPay)
	px.Pay()

	thPay := &ThirdPay{}
	px.SetPayBehavior(thPay)
	px.Pay()
}

/*
策略模式主要用于允许我们的程序在运行时动态更改一个任务的处理逻辑，
常见的应用场景有针对软件用户群体的不同策略切换（用一个烂大街的词儿表达就是千人千面）和业务流程兜底切换。
策略模式要解决的问题是，让使用客户端跟具体执行任务的策略解耦，不管使用哪种策略完成任务，不需要更改客户端使用策略的方式。
*/

// PayBehavior 抽象策略接口
type PayBehavior interface {
	OrderPay(px *PayCtx)
}

// PayCtx 支付行为的上下文
type PayCtx struct {
	// 提供支付能力的接口实现
	payBehavior PayBehavior
	// 支付参数
	payParams map[string]interface{}
}

func (px *PayCtx) SetPayBehavior(p PayBehavior) {
	px.payBehavior = p
}

func (px *PayCtx) Pay() {
	px.payBehavior.OrderPay(px)
}

func NewPayCtx(p PayBehavior) *PayCtx {
	params := map[string]interface{}{
		"appId": "234fdfdngj4",
		"mchId": 123456,
	}

	return &PayCtx{
		payBehavior: p,
		payParams:   params,
	}
}

// WXPay 具体策略实现
type WXPay struct{}

func (wxp *WXPay) OrderPay(px *PayCtx) {
	fmt.Printf("Wx支付加工支付请求 %v\n", px.payParams)
	fmt.Println("正在使用Wx支付进行支付")
}

// ThirdPay 具体策略实现
type ThirdPay struct{}

func (*ThirdPay) OrderPay(px *PayCtx) {
	fmt.Printf("三方支付加工支付请求 %v\n", px.payParams)
	fmt.Println("正在使用三方支付进行支付")
}

/*
策略模式和模版模式经常配合使用，策略模式是让完成某个任务的具体方式可以相互切换，而模版模式则是针对一个流程的共性梳理出固定的执行步骤
具体步骤的执行方式下放给子类来实现。两者解耦的维度不一样，策略模式在抽象方法的实现里，经常会用到模板模式。
还是拿我们上面的支付行为举例子。上面策略模式定义了一个算法族（支付），以及多个具体算法实现（微信、三方支付），让支付策略对客户端解耦。
*/
